/*This file is part of WZLibCP.

 *  WZLibCP is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

 *  WZLibCP is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License
    along with WZLibCP.  If not, see <http://www.gnu.org/licenses/>.
		
	Author: calc0000
*/
#include "stdafx.h"
#include "WZFile.h"

#include <sstream>

#include "WZFileHeader.h"
#include "WZDirectory.h"
#include "WZLibUtils.h"

using namespace std;

namespace WZLib{
	short			WZFile::fileVersion(){return this->_fileVersion;}
	WZDirectory*	WZFile::wzDir(){return this->_wzDir;}
	ctor WZFile::WZFile(string filePath){
		this->_header=NULL;
		this->_wzDir=NULL;
		this->_path=filePath;
		this->_name=getFileName(filePath);
		this->_fileVersion=-1;
		this->_version=this->_versionHash=0;
		this->_type=File;
		this->_reader=NULL;
	}
	dtor WZFile::~WZFile(){
		delete this->_header;
		delete this->_wzDir;
		this->_reader->Close();
		delete this->_reader;
	}
	void WZFile::unparse(){
		delete this->_header;
		delete this->_wzDir;
		this->_reader->Close();
		delete this->_reader;
		this->_parsed=false;
	}
	unsigned int WZFile::getVersionHash(int encver,int realver){
		stringstream ss;
		string versionNumberStr;
		int versionHash=0;
		int a,b,c,d;
		unsigned int ret=0;
		ss<<realver;
		versionNumberStr=ss.str();
		for(unsigned int i=0,l=versionNumberStr.size();i<l;i++){
			versionHash=(32*versionHash)+(int)versionNumberStr[i]+1;
		}
		a=(versionHash>>24)&0xFF;
		b=(versionHash>>16)&0xFF;
		c=(versionHash>> 8)&0xFF;
		d=(versionHash    )&0xFF;
		ret=0xFF^a^b^c^d;
		if(ret==encver)
			return versionHash;
		return 0;
	}
	ErrorCode WZFile::parse(WZBinaryReader* reader){
		if(this->_path=="")
			return Error_WZLib_WZFile_Parse_InvalidFilePath;
		reader=new WZBinaryReader(this->_path.c_str());
		if(!(reader->Opened()))
			return Error_WZLib_WZFile_Parse_InvalidFilePath;
		this->_reader=reader;
		this->_header=new WZFileHeader();
		this->_header->parse(reader);
		reader->header=this->_header;
		this->_version=reader->ReadInt16();
		if(this->_fileVersion==-1){
			for(int j=1;j<0x7F;j++){
				this->_fileVersion=j;
				this->_versionHash=this->getVersionHash(this->_version,this->_fileVersion);
				if(this->_versionHash!=0)
					break;
			}
		}
		reader->header->versionHash()=this->_versionHash;
		this->_wzDir=new WZDirectory(this->_name+" dir");
		(*(this->_wzDir->parent()))=this;
		this->_parsed=true;
		return this->_wzDir->parse(reader);
	}
	WZFile* WZFile::Open(std::string filePath, bool searchSearchDirectory){
		std::string path=filePath;
		FILE* checkF=fopen(path.c_str(),"rb");
		if(checkF==NULL && searchSearchDirectory){
			path=WZLib::WZConfig::wzSearchDir+filePath;
			checkF=fopen(filePath.c_str(),"rb");
		}
		bool ex=checkF!=NULL;
		if(checkF!=NULL)
			fclose(checkF);
		if(!ex)
			return NULL;
		return new WZFile(path);
	}
};